home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / programer2 / euclidlib / c / example < prev    next >
Text File  |  1992-04-21  |  17KB  |  606 lines

  1. /**** example.c ****/
  2. /* Program to show the euclid library in action */
  3. /* By Paul Field
  4.  * See !ReadMe file for distribution/modification restrictions
  5.  */
  6.  
  7. #include <assert.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <math.h>
  11.  
  12. #include "cache.h"
  13. #include "function.h"
  14. #include "ewindow.h"
  15. #include "euclid.h"
  16.  
  17. #include "alarm.h"
  18. #include "baricon.h"
  19. #include "dbox.h"
  20. #include "event.h"
  21. #include "flex.h"
  22. #include "heap.h"
  23. #include "kernel.h"
  24. #include "menu.h"
  25. #include "res.h"
  26. #include "resspr.h"
  27. #include "saveas.h"
  28. #include "template.h"
  29. #include "visdelay.h"
  30. #include "werr.h"
  31. #include "wimp.h"
  32. #include "wimpt.h"
  33. #include "win.h"
  34.  
  35.  
  36. /**** Some test functions followed by 'graphdata' for them    ****/
  37. /**** Functions are actually 2D Versions of Kenneth De Jong's ****/
  38. /**** Genetic Algorithm test functions                        ****/
  39.  
  40. static double fn1(double x, double y)
  41.  { return((x*x+y*y)*0.25-6);
  42.    /* Scaled by 0.25 - otherwise it looks very tall and thin */
  43.    /* -6 to centre it */
  44.  }
  45.  
  46. static double fn3(double x, double y)
  47.  { int total;
  48.  
  49.    total = (int)x + (int)y;
  50.    return((double)total);
  51.  }
  52.  
  53. static double fn5(double x, double y)
  54.  { static int a[2][25] =
  55.      { {-2,-2,-2,-2,-2,-1,-1,-1,-1,-1, 0, 0,0,0,0, 1, 1, 1, 1,1, 2, 2,2,2,2},
  56.        {-2,-1, 0, 1, 2,-2,-1, 0, 1, 2,-2,-1,0,1,2,-2,-1, 0, 1,2,-2,-1,0,1,2} };
  57.    int j;
  58.    double total = 0.002;
  59.  
  60.    for (j = 0; j <= 24; j++)
  61.     { double subtotal;
  62.  
  63.       subtotal = pow(x-(double)(a[0][j])*10.0,6) + pow(y-(double)(a[1][j])*10.0,6);
  64.       total += 1.0/((double)j+1.0+subtotal);
  65.     }
  66.    return(total*150-50);  /* Scaled by 150 - otherwise you can't see anything */
  67.                           /* -50 to centre it */
  68.  }
  69.  
  70. #define GRAPHS 3   /* If you change this then change the menu definitions */
  71.  
  72. static graphdata graph[GRAPHS] =
  73.  { { -5.12,5.12,
  74.      -5.12,5.12,
  75.      20, 700,
  76.      fn1, "Graph1", 0
  77.    },
  78.    { -5.12,5.12,
  79.      -5.12,5.12,
  80.      30, 700,
  81.      fn3, "Graph2", 0
  82.    },
  83.    { -65.536,65.536,
  84.      -65.536,65.536,
  85.      20, 700,
  86.      fn5, "Graph3", 0
  87.    }
  88.  };
  89.  
  90.  
  91. /***** Now for the main wimp program *****/
  92.  
  93. #define VERSION "0.02"
  94.  
  95. #define info_version 4   /* 'Version' icon number in info box */
  96.  
  97. /********* Messages ********/
  98.  
  99. #define MESS_CRMENU "Unable to create menu."
  100. #define MESS_ATMENU "Unable to attatch menu."
  101. #define MESS_NOINFO "Cannot create the info box."
  102. #define MESS_NOMEM  "Not enough memory."
  103.  
  104. /********* Useful filetypes *********/
  105.  
  106. #define ftype_sprite 0xff9
  107. #define ftype_euclid 0xde1
  108.  
  109.  
  110. /********* menu definition text ***********/
  111.  
  112. /**** Main menu ****/
  113.  
  114. #define MM_ITEMS ">Info,Graph1,Graph2,Graph3,Quit"
  115. typedef enum
  116.  { mm_info=1, mm_graph1, mm_graph2, mm_graph3, mm_quit
  117.  }mm_item;
  118.  
  119. /**** Graph menu ****/
  120.  
  121. #define GM_ITEMS "Save,Style,Sprite,Rotate"
  122. typedef enum
  123.  { gm_save=1, gm_style, gm_sprite, gm_rotate
  124.  }gm_item;
  125.  
  126. /**** Save menu ****/
  127.  
  128. #define SM_ITEMS ">Euclid,>Sprite"
  129. typedef enum
  130.  { sm_euclid=1, sm_sprite
  131.  }sm_item;
  132.  
  133. /**** Style menu ****/
  134.  
  135. #define STM_ITEMS "Faces Only,Faces & Edges,Ray Trace|Lit"
  136. typedef enum
  137.  { stm_faces=1, stm_facesedges, stm_raytrace, stm_lit
  138.  }stm_item;
  139.  
  140. /**** Sprite options menu ****/
  141.  
  142. #define SOM_ITEMS "Multitask,Mode"
  143. typedef enum
  144.  { som_multitask = 1, som_mode
  145.  }som_item;
  146.  
  147. /**** Multitask menu ****/
  148.  
  149. #define MTM_ITEMS "None,Slow,Fast,VFast"
  150. typedef enum
  151.  { mtm_none=1, mtm_slow, mtm_fast, mtm_vfast
  152.  }mtm_item;
  153.  
  154. /**** Mode menu ****/
  155.  
  156. #define MDM_ITEMS "Current,Dynamic,num"
  157. typedef enum
  158.  { mdm_current=1, mdm_dynamic, mdm_num
  159.  }mdm_item;
  160.  
  161. /**** Global menu variables ****/
  162.  
  163. static menu mainmenu, graphmenu, savemenu, spritemenu, multimenu, modemenu, stylemenu;
  164. static char modestring[4];
  165.  
  166.  
  167. /********* Various global variables *********/
  168.  
  169. #define SIZE        30*1024 /* Amount of memory set aside for each graph */
  170. #define ROTATEEVERY 10  /* Graph tries to rotate at 100/ROTATEEVERY frames per second */
  171.  
  172.  
  173. typedef struct graphwinfo
  174.  { int                graphno;
  175.    euclid_header     *structure;
  176.    ewindow            ew;
  177.    BOOL               closed;     /* TRUE if window to graph is closed */
  178.    BOOL               rotate;     /* TRUE if graph is rotating in the window */
  179.    BOOL               sprite;     /* TRUE if window is using 'sprite' mode */
  180.    mtm_item           multitask;  /* Type of multitasking */
  181.    ewindow_spritemode mode;
  182.    euclid_mainstyle   style;      /* Drawing style of the picture */
  183.    BOOL               lit;
  184.  }graphwinfo;
  185.  
  186. static graphwinfo gwi[GRAPHS];
  187. static void *cache[GRAPHS];       /* Block of memory used by Euclid for drawing */
  188.  
  189.  
  190. /********* Error handling macros ********/
  191.  
  192. #define ERR_NonFatal 0
  193. #define ERR_Fatal    1
  194.  
  195. #define main_error(error)     werr(ERR_NonFatal, error)
  196. #define main_terminate(error) werr(ERR_Fatal, error)
  197.  
  198.  
  199. /********** The program **********/
  200.  
  201. static void main_initcaches(void);
  202. static void main_createmenus(void);
  203. static void main_decodemainmenu(void *dummy, char *hit);
  204. static menu main_makegraphmenu(void *handle);
  205. static void main_decodegraphmenu(void *dummy, char *hit);
  206. static void main_setgraphstyle(graphwinfo *gwientry);
  207. static BOOL main_creategraph(int graphno);
  208. static euclid_header *main_createstructure(graphdata *g, void *cache);
  209. static void main_close(ewindow, void *closed);
  210. static void main_programinfo(void);
  211. static void main_barclick(wimp_i dummy);
  212. static void main_rotategraph(int, void *handle);
  213. static BOOL main_saveeuclid(char *name, void *handle);
  214. static BOOL main_savesprite(char *name, void *handle);
  215.  
  216.  
  217. int main(void)
  218.  { int graphno;
  219.  
  220.    wimpt_init("Euclid Library Example");
  221.    res_init("Example");
  222.    resspr_init();
  223.    template_init();
  224.    dbox_init();
  225.    alarm_init();
  226.    flex_init();
  227.    visdelay_init();
  228.    heap_init(TRUE);
  229.  
  230.    main_initcaches();
  231.    for (graphno = 0; graphno < GRAPHS; graphno++)
  232.     { gwi[graphno].structure = NULL;
  233.       gwi[graphno].graphno   = graphno;
  234.       gwi[graphno].closed    = TRUE;
  235.       gwi[graphno].rotate    = FALSE;
  236.     }
  237.    main_createmenus();
  238.    baricon("!Example",(int) resspr_area(), main_barclick);
  239.    if (!event_attachmenu(win_ICONBAR, mainmenu, main_decodemainmenu, NULL))
  240.     { main_terminate(MESS_ATMENU);
  241.     }
  242.    while(TRUE)
  243.     { event_process();
  244.     }
  245.    return(0);
  246.  }
  247.  
  248. static void main_initcaches(void)
  249.  { int cachesize;
  250.    BOOL seperate;
  251.    int cacheno;
  252.    char var[5];
  253.  
  254.    /** Get and check the size of the drawing cache(s) **/
  255.    os_read_var_val("Example$Cachesize",var,5);
  256.    if (!*var)
  257.     { main_terminate("Example$Cachesize not defined");
  258.     }
  259.    if ((cachesize = atoi(var)*1024) < 10*1024)
  260.     { main_terminate("Example$Cachesize must be greater than or equal to 10");
  261.     }
  262.  
  263.    /** Decide on a single or multiple caches **/
  264.    os_read_var_val("Example$Seperatecaches",var,5);
  265.    if (!*var)
  266.     { main_terminate("Example$Seperatecaches not defined");
  267.     }
  268.    if (!strcmp(var, "yes"))
  269.     { seperate = TRUE;
  270.     }
  271.    else
  272.     { if ((seperate = strcmp(var, "no")) != 0)
  273.        { main_terminate("Example$Seperatecaches must have a value of 'yes' or 'no' "
  274.                         "(Note: lower case)");
  275.        }
  276.     }
  277.  
  278.    /** Single cache - assign memory to cache[0] copy reference to cache[1] etc.. **/
  279.    /** Multiple caches - assign memory to each **/
  280.    cacheno = 0;
  281.    do
  282.     { if ((cache[cacheno] = heap_alloc(cachesize)) == NULL)
  283.        { main_terminate(MESS_NOMEM);
  284.        }
  285.       *(unsigned int *)cache[cacheno] = cachesize;
  286.     }
  287.    while(++cacheno < GRAPHS && seperate);
  288.    for (;cacheno < GRAPHS; cacheno++)
  289.     { cache[cacheno] = cache[0];
  290.     }
  291.  }
  292.  
  293.  
  294. /***** Creating and decoding menus *****/
  295.  
  296. static void main_createmenus(void)
  297.  { if ((mainmenu  = menu_new("Example",  MM_ITEMS))  == NULL ||
  298.        (graphmenu = menu_new("Graph",    GM_ITEMS))  == NULL ||
  299.        (savemenu  = menu_new("Save",     SM_ITEMS))  == NULL ||
  300.        (stylemenu = menu_new("Style",    STM_ITEMS)) == NULL ||
  301.        (spritemenu= menu_new("Sprite",   SOM_ITEMS)) == NULL ||
  302.        (multimenu = menu_new("Multitask",MTM_ITEMS)) == NULL ||
  303.        (modemenu  = menu_new("Mode",     MDM_ITEMS)) == NULL)
  304.     { main_terminate(MESS_CRMENU);
  305.     }
  306.    menu_make_writeable(modemenu, mdm_num, modestring, 4, "A0-9");
  307.    menu_submenu(spritemenu, som_multitask, multimenu);
  308.    menu_submenu(spritemenu, som_mode, modemenu);
  309.    menu_submenu(graphmenu, gm_save, savemenu);
  310.    menu_submenu(graphmenu, gm_style, stylemenu);
  311.    menu_submenu(graphmenu, gm_sprite, spritemenu);
  312.  }
  313.  
  314.  
  315. static void main_decodemainmenu(void *dummy, char *hit)
  316.  { dummy=dummy;
  317.  
  318.    switch(hit[0])
  319.     { case mm_info  : main_programinfo(); return;
  320.       case mm_quit  : exit(0);
  321.     }
  322.    if (hit[0] != 0)
  323.     { int graphno;
  324.       graphwinfo *gwientry;
  325.  
  326.       graphno = hit[0]-mm_graph1;
  327.       gwientry = &gwi[graphno];
  328.       if (gwientry->structure == NULL)
  329.        { main_creategraph(graphno);
  330.        }
  331.       if (gwientry->structure != NULL)
  332.        { ewindow_open(gwientry->ew);
  333.          gwientry->closed = FALSE;
  334.          if (gwientry->rotate)
  335.           { main_rotategraph(0, gwientry);
  336.           }
  337.          menu_setflags(mainmenu, hit[0], TRUE, FALSE);
  338.        }
  339.     }
  340.  }
  341.  
  342. static menu main_makegraphmenu(void *handle)
  343.  { graphwinfo *gwientry = handle;
  344.    int option;
  345.    BOOL rayok;     /* TRUE if raytracing can occur */
  346.    BOOL rayactive; /* TRUE if raytracing is occuring */
  347.  
  348.    rayok = ewindow_hassprite(gwientry->ew) && gwientry->mode != ewindow_smdynamic &&
  349.            gwientry->multitask != mtm_none && !gwientry->rotate;
  350.    rayactive = gwientry->style == emainstyle_raytrace;
  351.  
  352.    menu_setflags(graphmenu, gm_sprite, gwientry->sprite, FALSE);
  353.    menu_setflags(graphmenu, gm_rotate, gwientry->rotate, rayactive);
  354.    menu_setflags(multimenu, mtm_none, gwientry->multitask == mtm_none, rayactive);
  355.    for (option = mtm_none+1; option <= mtm_vfast; option++)
  356.     { menu_setflags(multimenu, option, gwientry->multitask == option, FALSE);
  357.     }
  358.    if (gwientry->mode >= 0)
  359.     { sprintf(modestring, "%d", gwientry->mode);
  360.     }
  361.    else
  362.     { *modestring = NULL;
  363.     }
  364.    menu_setflags(modemenu, mdm_current, gwientry->mode == ewindow_smcurrent, FALSE);
  365.    menu_setflags(modemenu, mdm_dynamic, gwientry->mode == ewindow_smdynamic, rayactive);
  366.    menu_setflags(savemenu, sm_sprite, FALSE, !ewindow_updatecomplete(gwientry->ew) ||
  367.                                              !ewindow_hassprite(gwientry->ew));
  368.    for (option = stm_faces; option < stm_raytrace; option++)
  369.     { menu_setflags(stylemenu, option, gwientry->style == option-1, FALSE);
  370.     }
  371.    menu_setflags(stylemenu, stm_raytrace, gwientry->style == stm_raytrace-1, !rayok);
  372.    menu_setflags(stylemenu, stm_lit, gwientry->lit, FALSE);
  373.    return(graphmenu);
  374.  }
  375.  
  376. static void main_decodegraphmenu(void *handle, char *hit)
  377.  { graphwinfo *gwientry = handle;
  378.  
  379.    switch(hit[0])
  380.     { case gm_save:
  381.         switch(hit[1])
  382.          { case sm_euclid:
  383.              saveas(ftype_euclid, "Euclid", SIZE, main_saveeuclid, 0,0, gwientry);
  384.              break;
  385.            case sm_sprite:
  386.              saveas(ftype_sprite, "Sprite", 0, main_savesprite, 0,0, gwientry);
  387.              break;
  388.          }
  389.         break;
  390.       case gm_style:
  391.         switch(hit[1])
  392.          { case stm_raytrace :
  393.            case stm_faces :
  394.            case stm_facesedges :
  395.              gwientry->style = hit[1]-1;
  396.              break;
  397.            case stm_lit :
  398.              gwientry->lit = !gwientry->lit;
  399.          }
  400.         main_setgraphstyle(gwientry);
  401.         break;
  402.       case gm_sprite:
  403.         switch(hit[1])
  404.          { case 0:
  405.              gwientry->sprite = !gwientry->sprite;
  406.              if (gwientry->style == emainstyle_raytrace)
  407.               { main_error("Changing to faces only style.");
  408.                 gwientry->style = emainstyle_facesonly;
  409.                 main_setgraphstyle(gwientry);
  410.               }
  411.              break;
  412.            case som_multitask:
  413.              if (hit[2] != 0)
  414.               { gwientry->multitask = hit[2];
  415.               }
  416.              switch(hit[2])
  417.               { case mtm_none  : ewindow_timing(gwientry->ew,    0, 0);  break;
  418.                 case mtm_slow  : ewindow_timing(gwientry->ew,    1, 2);  break;
  419.                 case mtm_fast  : ewindow_timing(gwientry->ew,   10, 2);  break;
  420.                 case mtm_vfast : ewindow_timing(gwientry->ew, 0xfe, 2);  break;
  421.               }
  422.              break;
  423.            case som_mode:
  424.              switch(hit[2])
  425.               { case mdm_current  : gwientry->mode = ewindow_smcurrent;   break;
  426.                 case mdm_dynamic  : gwientry->mode = ewindow_smdynamic;   break;
  427.                 case mdm_num      : gwientry->mode = atoi(modestring);    break;
  428.               }
  429.              break;
  430.          }
  431.         ewindow_usesprite(gwientry->ew, gwientry->sprite, gwientry->mode);
  432.         break;
  433.       case gm_rotate:
  434.         gwientry->rotate = !gwientry->rotate;
  435.         if (gwientry->rotate)
  436.          { main_rotategraph(0, gwientry);
  437.          }
  438.         else
  439.          { alarm_removeall(gwientry);
  440.          }
  441.         break;
  442.     }
  443.  }
  444.  
  445.  
  446. /***** Creating and handling graphwindows *****/
  447.  
  448. static void main_setgraphstyle(graphwinfo *gwientry)
  449.  { ewindow_setstyle(gwientry->ew, edrawstyle_mainstyle * gwientry->style +
  450.                     gwientry->lit * (edrawstyle_lightson|edrawstyle_frontlighton));
  451.  }
  452.  
  453.  
  454. #define GRAPHSTYLE ((edrawstyle_mainstyle * emainstyle_facesonly) |\
  455.                     edrawstyle_lightson | edrawstyle_frontlighton)
  456.  
  457. static BOOL main_creategraph(int graphno)
  458.  { char          *error = NULL;
  459.    graphwinfo    *gwientry;
  460.    euclid_header *structure;
  461.    wimp_wind     *window;
  462.  
  463.    gwientry = &gwi[graphno];
  464.    if ((window = template_syshandle("ewindow")) == NULL)
  465.     { main_error("Template 'ewindow' not found");
  466.       return(FALSE);
  467.     }
  468.    window->box.y0 -= 40; /* Move each graph window down slightly */
  469.    window->box.y1 -= 40;
  470.  
  471.    if ((structure = main_createstructure(&graph[graphno], cache[graphno])) != NULL &&
  472.        (gwientry->ew = ewindow_create(graph[graphno].name, GRAPHSTYLE, structure,
  473.                                       NULL, main_close, gwientry)) != NULL)
  474.     { if (!event_attachmenumaker(ewindow_handle(gwientry->ew), main_makegraphmenu,
  475.                                  main_decodegraphmenu, gwientry))
  476.        { error = MESS_ATMENU;
  477.          ewindow_destroy(gwientry->ew);
  478.        }
  479.     }
  480.    else
  481.     { error = MESS_NOMEM;
  482.     }
  483.  
  484.    if (error)
  485.     { main_error(error);
  486.       if (structure != NULL)
  487.        { heap_free(structure);
  488.        }
  489.       structure = NULL;
  490.     }
  491.    else
  492.     { gwientry->structure = structure;
  493.       gwientry->multitask = mtm_none;
  494.       gwientry->mode      = ewindow_smdynamic;
  495.       gwientry->style     = emainstyle_facesonly;
  496.       gwientry->lit       = TRUE;
  497.       main_setgraphstyle(gwientry);
  498.     }
  499.    return(error == NULL);
  500.  }
  501.  
  502.  
  503. static euclid_header *main_createstructure(graphdata *g, void *cache)
  504.  { euclid_header *data;
  505.  
  506.    if ((data = heap_alloc(SIZE)) != NULL)
  507.     { visdelay_begin();
  508.  
  509.       wimpt_noerr(euclid_initialise(einitflags_blackonwhite, data, SIZE, NULL));
  510.       if (!wimpt_complain(function_makegraph(data, g, (euclid_mesh **)&data->root)))
  511.        { data->observerrot.x = 0<<6;
  512.          data->observerrot.y = 80<<6;
  513.          data->observerrot.z = 90<<6;
  514.          data->cache = cache;
  515.          data->backgroundcol.c.abscolour = euclid_makecolour(0x80u,0,0xa0,0xff);
  516.        }
  517.       else
  518.        { heap_free(data);
  519.          data = NULL;
  520.        }
  521.       visdelay_end();
  522.     }
  523.    return(data);
  524.  }
  525.  
  526.  
  527. static void main_close(ewindow ew, void *vgwi)
  528.  { graphwinfo *gwi = vgwi;
  529.  
  530.    if (gwi->rotate)
  531.     { alarm_removeall(gwi);
  532.     }
  533.    gwi->closed = TRUE;
  534.    menu_setflags(mainmenu, gwi->graphno + mm_graph1, FALSE, FALSE);
  535.    ewindow_closeoptions(ew, gwi->style != emainstyle_raytrace);
  536.    ewindow_close(ew);
  537.  }
  538.  
  539.  
  540. /***** Miscellaneous functions *****/
  541.  
  542. static void main_programinfo(void)
  543.  { dbox d;
  544.    char versionstring[80];
  545.  
  546.    if ((d = dbox_new("progInfo")) == NULL)
  547.     { main_error(MESS_NOINFO);
  548.       return;
  549.     }
  550.    sprintf(versionstring, "%s (%s)", VERSION, __DATE__);
  551.    dbox_setfield(d, info_version, versionstring);
  552.  
  553.    dbox_show(d);
  554.    dbox_fillin(d);
  555.    dbox_dispose(&d);
  556.  }
  557.  
  558.  
  559. static void main_barclick(wimp_i dummy)
  560.  { dummy = dummy;                
  561.    /* Need to register a function with 'baricon' otherwise clicking */
  562.    /* on the icon bar icon causes the program to crash. */
  563.  }
  564.  
  565.  
  566. static void main_rotategraph(int time, void *handle)
  567.  { graphwinfo *gwientry = handle;
  568.    int angle;
  569.  
  570.    time=time;
  571.    if (ewindow_updatecomplete(gwientry->ew))
  572.     { angle = gwientry->structure->observerrot.x>>6;
  573.       angle = (angle+10)%360;
  574.       gwientry->structure->observerrot.x = angle<<6;
  575.       ewindow_update(gwientry->ew);
  576.     }
  577.    alarm_set(alarm_timenow()+ROTATEEVERY, main_rotategraph, handle);
  578.  }
  579.  
  580.  
  581. /***** Saving functions *****/
  582.  
  583. static BOOL main_saveeuclid(char *name, void *handle)
  584.  { graphwinfo  *gwientry = handle;
  585.  
  586.    return(wimpt_complain(euclid_save(gwientry->structure, name)) == NULL);
  587.  }
  588.  
  589.  
  590. static BOOL main_savesprite(char *name, void *handle)
  591.  { graphwinfo  *gwientry = handle;
  592.    sprite_area **area;
  593.    int         offset;
  594.    BOOL ok;
  595.  
  596.    if (ewindow_sprite(gwientry->ew, &area, &offset))
  597.     { ok = (wimpt_complain(sprite_area_save(*area, name)) == NULL);
  598.     }
  599.    else
  600.     { /* I don't think this can happen - but better safe than sorry */
  601.       main_error("The sprite memory has been freed - cannot save.");
  602.       ok = FALSE;
  603.     }
  604.    return(ok);
  605.  }
  606.